import math
from pydoc import text
import pyautogui
import time
import random
import os
import datetime
import json
import json
import os
import sys
import threading
import queue
import pyperclip
import win32gui
import win32process
import psutil
import subprocess
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, 
                            QTextEdit, QVBoxLayout, QWidget)
from PyQt5.QtCore import Qt, QTimer, QObject, pyqtSignal
from app.interface_walmart.MySQLHelper_walmart import MySQLHelper
import uuid
import random
from datetime import datetime
import traceback
import requests
import base64
import math
import time
import pygetwindow as gw
import win32con
from baidu_location import baidu_location
from follow_baidu_last import get_baidu3_location_json

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.start_btn.click()
        self.show()
        sql='select * from app_zbirdaccount where is_active=1'
        ziniaoaccount=self.dbhelper.query(sql)
        # print(ziniaoaccount)
        for row in ziniaoaccount:
            print(row['loginname'])
            print(row['password'])
            self.ziniao_login(row['id'],row['loginname'],row['password'])
        
    def init_ui(self):
        self.setWindowTitle('RPA跟卖')
        self.setGeometry(100, 100, 800, 600)
        self.start_btn = QPushButton('开始跟卖任务', self)
        self.start_btn.clicked.connect(self.start_task)
        self.text_memo = QTextEdit(self)
        self.text_memo.setReadOnly(True)
        layout = QVBoxLayout()
        layout.addWidget(self.start_btn)
        layout.addWidget(self.text_memo)
        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)
        self.dbhelper=MySQLHelper()
        # self.close_windows_by_processname('ziniao.exe')

        
    def start_task(self):
        """启动任务线程"""

        current_dir = os.getcwd()
        json_file_path = os.path.join(current_dir, 'app', 'interface', 'rpa_login.json')
        self.start_btn.setEnabled(False)
    def ziniao_login(self,zbird_account_id,ziniaoaccount,ziniaopassword):
        # self.check_country_origin_in_active_window()
 
        current_dir = os.getcwd()
        image_dirpath = os.path.join(current_dir, 'app', 'interface','png')
        # locaopen=pyautogui.locateOnScreen(image_path)
        # if locaopen:    
        #     print(locaopen)
        #     time.sleep(2.5)
        self.text_memo.append("开始执行任务...\n")
        self.text_memo.append("正在启动紫鸟客户端...\n")
        pyautogui.FAILSAFE = True
        pyautogui.PAUSE = 1
        orderindex=0
        addtionalheight=(orderindex -1)*88
        # 进行登录操作
        sql=f'select * from app_walmartaccount  where zbird_account_id={zbird_account_id}'
        walmartaccount=self.dbhelper.query(sql)
        if len(walmartaccount)==0:
            return
        subprocess.Popen(r"F:\Program Files\ziniao\ziniao.exe")
        time.sleep(0.5*random.random())
        self.set_window_position('ziniao.exe',1439,5,480,1000)

        pyautogui.click(1601,29)
        print('设置窗口位置')
        pyautogui.click(1518,370)
        # 第三步张林余002
        time.sleep(6.5)
        # 输入登录账号
        print('输入登录账号')
        pyautogui.click(1800, 472)
        pyautogui.press('backspace', presses=20)
        time.sleep(0.5)
        pyperclip.copy(ziniaoaccount)
        pyautogui.hotkey('ctrl', 'v') 
        # 第四步
        print('输入登录密码')
        pyautogui.click(1550, 542)
        pyautogui.press('backspace', presses=20)
        time.sleep(0.5)
        pyautogui.write( ziniaopassword,interval=0.1)
        print('输入密码后，按下回车')
        pyautogui.press('enter', presses=2)
        dirpath=os.path.join(os.getcwd(),'screenshot')
        os.makedirs(dirpath,exist_ok=True)
        # 直接登录了，直接登录了。进入紫鸟ziniaobrowser.exe界面
        time.sleep(5.5)
        print(f'当前沃尔玛账号数量:{len(walmartaccount)}')
        for row2 in walmartaccount:
            sql2=f'select * from app_skus_new  where is_following=1 and (upc is not null and   LENGTH(upc) > 6 ) and walmart_account_id={row2["id"]}'
            print(sql2)
            data_app_skus=self.dbhelper.query(sql2)
            print(f'当前跟卖sku数量:{len(data_app_skus)}')
            if len(data_app_skus)>0:
                orderindex=row2['orderindex']
                # orderindex=2
                addtionalheight=(orderindex -1)*88
                # 打开一个沃尔玛新账号前，关闭窗口；
                self.close_windows_by_processname('ziniaobrowser.exe')
                # 第六步，等待出现新页面，在这里，选择账号，需要按照每个沃尔玛账号的顺序，进行点击
                self.human_like_move_and_click(1837, 246 + addtionalheight)
                time.sleep(5.5)
                self.set_window_position('ziniaobrowser.exe',1,1)
                time.sleep(0.5)
                pyautogui.hotkey('ctrl', 'tab')
                self.set_window_position('ziniaobrowser.exe',1,0,1016,1006)
                image1=os.path.join(image_dirpath,'visitmany.png')
                center1=self.get_location_by_image(image1)
                while center1 is None:  
                    time.sleep(1)
                    center1=self.get_location_by_image(image1)
                    print('没有找到visitmany')
                if center1:
                    self.human_like_move_and_click(center1[0],center1[1])
                else:
                    print('没有找到visitmany')
                image2=os.path.join(image_dirpath,'openaccount.png')
                center_openaccount=self.get_location_by_image(image2)
                if center_openaccount:
                    self.human_like_move_and_click(center_openaccount[0],center_openaccount[1])
                    time.sleep(2.5)
                else:
                    print('没有找到openaccount')
                # 第七步，等待出现新页面
                # time.sleep(5.5)
                images=['visitmany.png','openaccount.png','login.png','catalog.png','additems.png']   
                for index,image in enumerate(images,start=1):
                    image_path=os.path.join(image_dirpath,image)
                    center=self.get_location_by_image(image_path)
                    while center is None:  
                        time.sleep(1)
                        center=self.get_location_by_image(image_path)
                        print(f'没有找到{image}')
                    if center:
                        self.human_like_move_and_click(center[0],center[1])
                    else:
                        print(f'没有找到{image}图片')
                
                print('首页-><-'*5,'这个页面，就是正常沃尔玛的首页了。')
                json_result=self.shoot_to_json_result()
                words1='Catalog' #404,-21
                for ix  in range(1):
                    itemlocation=self.get_text_location_inwindow(json_result,words1)
                    if itemlocation:
                        print(itemlocation['location'])
                        self.human_like_move_and_click(itemlocation['location']['left'],itemlocation['location']['top'])
                        time.sleep(2.5)
                        # 下面的动作点击add item
                        self.human_like_move_and_click(itemlocation['location']['left'] + 404*2,itemlocation['location']['top'] - 21)
                        time.sleep(2.5)
                self.ziniao_follow(json_result,row2 ,data_app_skus)   
    def ziniao_follow(self,json_result,row_walmart_account,data_app_skus):  
        addtionprice=12
        username=row_walmart_account['username']
        now = datetime.now()
        self.set_window_position('ziniaobrowser.exe',1,0,1016,1006)
        code_part =random.choice("ABCDEF")                  # 固定代号
        year_part = str(now.year)[-1]      # 年份最后一位
        month_part = f"{now.month:02d}"    # 两位数月份
        prefix_part =random.choice("GHIJKLM")                # 固定前缀
        for index,row in enumerate(data_app_skus,start=1) :
            try:
                print(row['sku'])
                # pyautogui.scroll(200)
                full_uuid = str(uuid.uuid4())
                first_segment = full_uuid.split('-')[0]
                leng1=random.randint(3,len(first_segment)-2)
                serial_part =first_segment[:leng1] # 4位序
                sku=row['sku']
                price=row['price']
                new_sku_code=f"{code_part}{year_part}{month_part}{prefix_part}{serial_part}"
                print(new_sku_code)
                sql=f'select * from sku_keywords_history where sku="{sku}" and abs(toprice-{price})>0.01'
                data_sku_keywords_history=self.dbhelper.query(sql)
                print(sql)
                if len(data_sku_keywords_history)==0:
                    if index==1:
                        self.human_like_move_and_click(337,834)
                    else:
                        json_result=self.shoot_to_json_result()
                        words1=['GTIN, UPC, EAN, ISBN']  #这里需要修改，分2次
                        for index2, wod in enumerate( words1,start=1):
                            itemlocation=self.get_text_location_inwindow(json_result,wod)
                            self.human_like_move_and_click(itemlocation['location']['left'],itemlocation['location']['top'])
                    pyautogui.press('backspace', presses=20)  # 按20次退格键
                    pyautogui.write(row['upc'], interval=0.1)
                    pyautogui.press('enter',presses=2)     
                    pyautogui.press('backspace', presses=20)
                    time.sleep(2.5) #下面点击2次，担心点不中，所以点了2次；目的是点击页面中第二个add 
                    if index==1:
                        self.human_like_move_and_click(256 ,754)
                        self.human_like_move_and_click(256 ,764)
                    else:
                        self.human_like_move_and_click(258, 743)
                        self.human_like_move_and_click(238, 771)
                        self.human_like_move_and_click(256 ,781)
                    time.sleep(2.5)

                    print('开始进入最后的更卖界面')
                    json_result=self.shoot_to_json_result()
                    timestamp = str(int(time.time() * 1000))[-6:]
                    random_length = random.randint(1, 3)
                    random_num = str(random.randint(10**(random_length - 1), 10**random_length - 1))
                    tax_numeric_id = timestamp + random_num
                    print('处理sku')
                    self.human_like_move_and_click(174, 401) 
                    pyautogui.write(new_sku_code, interval=0.1)
                    pyautogui.press('enter',presses=2)     
                    print('处理销售价格') 
                    self.human_like_move_and_click(526, 402)  
                    pyautogui.write(str(price+addtionprice), interval=0.1)
                    pyautogui.press('enter',presses=2)     
                    print('处理shipping weight')
                    self.human_like_move_and_click(217, 628)  
                    pyautogui.write('1', interval=0.1)
                    pyautogui.press('enter',presses=2)     
                    print('处理unit')
                    self.human_like_move_and_click(670, 647)  
                    self.human_like_move_and_click(631, 692)  
                    print('处理税码')
                    itemlocation_country=self.get_text_location_inwindow(json_result,'country')
                    if itemlocation_country:
                        print('发货地国家')
                        self.human_like_move_and_click(135, 835)  
                                # 移动鼠标到指定位置
                        self.human_like_move_and_click(496, 272)
                        # 模拟鼠标按下
                        # pyautogui.mouseDown()
                        # 短暂延迟，让按下动作有一定持续时间
                        # 向下滚动120个像素，在pyautogui中，负数表示向下滚动
                        for ix in range(13):
                            pyautogui.scroll(-240)
                            time.sleep(0.2*random.random())
                        pyautogui.click(300, 396) 
                        time.sleep(2.5)
                        self.human_like_move_and_click(517, 838)
                        pyautogui.write(tax_numeric_id, interval=0.1)
                        pyautogui.press('enter',presses=2)     
                        time.sleep(2.5)
                    else:
                        print('没有找到国家')
                        print('直接输入税码')
                        try:
                            self.human_like_move_and_click(77, 838)
                            pyautogui.write(tax_numeric_id, interval=0.1)
                            pyautogui.press('enter',presses=2)  
                        except Exception as e:
                            print(f'输入税码失败{e}')
                            traceback.print_exc()

                    print('点击submit')

                    self.human_like_move_and_click(892, 1022)
                    self.human_like_move_and_click(908, 100)
                    self.human_like_move_and_click(924, 979)
                    json_result=self.shoot_to_json_result()
                    itemlocation_submit=self.get_text_location_inwindow(json_result,'submit')
                    if itemlocation_submit:
                        print('submit')
                        self.human_like_move_and_click(itemlocation_submit['location']['left'],itemlocation_submit['location']['top'])  
                        # 移动鼠标到指定位置
                    else:
                        print('没有找到submit')
                        self.human_like_move_and_click(918, 987)
                    print('随意点击一个位置')
                    self.human_like_move_and_click(738,1004)
                    time.sleep(2.5)
                    json_result=self.shoot_to_json_result()
                    itemlocation_submit=self.get_text_location_inwindow(json_result,'Item successfully submitted')
                    if itemlocation_submit:
                        print('Item successfully submitted')
                        self.human_like_move_and_click(itemlocation_submit['location']['left'],itemlocation_submit['location']['top'])  
                        pyautogui.hotkey('ctrl', 'w') 
                        # 移动鼠标到指定位置                   
                        # 适用于大多数浏览器
                        time.sleep(0.2)
                        sql=f'insert into sku_keywords_history (sku,opdate,fromprice,toprice,username) values ("{sku}",now(),0,{price},"{username}")'
                        print(sql)
                        self.dbhelper.execute(sql)
                        sql=f'update app_skus_new set newsku="{new_sku_code}",newprice={price} where id={row["id"]}'
                        self.dbhelper.execute(sql)
            except Exception as e:
                print(f'跟卖失败{sku}->{new_sku_code}->{price}')
                traceback.print_exc()    
    def get_text_location_inwindow(self,json_result,text_tofind):
        try:
            # 获取当前活动窗口位置
            # 解析坐标
            target_coordinates = []
            if 'words_result' in json_result:
                for item in json_result['words_result']:
                    if text_tofind.lower() in item['words'].lower():
                        item['location']['left']=item['location']['left']+ int(item['location']['width']/2)
                        item['location']['top']=item['location']['top']+ int(item['location']['height']/2)
                        leftpos=item['location']['left']
                        toppos=item['location']['top']
                        sql=f"insert into app_text_location(textfind,leftpos,toppos) values('{text_tofind}',{leftpos},{toppos})"
                        print(sql)
                        self.dbhelper.updatesql(sql)
                        print(item)

                        return item # 获取文字区域顶点坐标（相对于截图）
            return False            

        except Exception as e:
            print(f"坐标获取失败: {str(e)}")
            traceback.print_exc()
            return []
    def get_location_by_image(self,image_path):
        try:
            if os.path.exists(image_path):
                locaopen=pyautogui.locateOnScreen(image_path)
                if locaopen:
                    center = pyautogui.center(locaopen)
                    # 点击图像中心

                    return center
                else:
                    return None
            else:
                return None
        except Exception as e:
            traceback.print_exc()
            return False

    def human_like_move_and_click(self,dest_x, dest_y, duration=0.4, click=True):
        try:
            # 获取初始位置
            start_x, start_y = pyautogui.position()
            # 计算移动路径参数
            distance = math.hypot(dest_x - start_x, dest_y - start_y)
            steps = max(int(distance / 150), 8)  # 至少10步
            step_time = duration / steps
            # 生成带扰动的移动路径
            for i in range(steps):
                # 使用缓动函数（easeOutQuad）
                t = (i + 1) / steps
                progress = 1 - (1 - t) ** 2
                current_x = start_x + (dest_x - start_x) * progress
                current_y = start_y + (dest_y - start_y) * progress
                # 添加随机扰动（不超过5像素）
                current_x += random.uniform(-3, 3)
                current_y += random.uniform(-3, 3)
                # 确保坐标在屏幕范围内
                current_x = max(0, min(pyautogui.size().width-100, current_x))
                current_y = max(0, min(pyautogui.size().height-100, current_y))
                pyautogui.moveTo(current_x, current_y, duration=step_time)
                # 添加随机延迟（最后几步更慢）
                if i > steps - 3:
                    time.sleep(random.uniform(0.02, 0.05))

            # 最终精确移动
            final_x = dest_x + random.randint(-2, 2)
            final_y = dest_y + random.randint(-2, 2)
            pyautogui.moveTo(final_x, final_y, duration=0.1)

            pyautogui.moveTo(final_x, final_y, duration=random.uniform(0.05, 0.15))
        
            if click:
                # 增加点击前犹豫（50%概率）
                if random.random() < 0.5:
                    time.sleep(random.uniform(0.1, 0.3))
                    
                # 模拟更真实的点击动作
                pyautogui.mouseDown()
                time.sleep(random.uniform(0.1, 0.3))  # 延长按压时间
                pyautogui.mouseUp()
                
                # 点击后停留（增加随机性）
                stay_duration = random.uniform(0.8, 2.5)  # 延长停留时间范围
                if stay_duration > 1.5:
                    # 添加微小移动模拟手指颤抖
                    for _ in range(2):
                        pyautogui.moveRel(
                            random.randint(-3, 3),
                            random.randint(-3, 3),
                            duration=0.05
                        )
                        time.sleep(0.05)
                time.sleep(stay_duration)
                
                # 50%概率在离开前轻微移动
                if random.random() < 0.5:
                    pyautogui.moveRel(
                        random.randint(-10, 10),
                        random.randint(-10, 10),
                        duration=random.uniform(0.5, 1.3)
                    )
        except Exception as e:
            print(f"鼠标移动失败: {str(e)}")     
    def shoot_to_json_result(self):
        screenshot=pyautogui.screenshot()
        timstamp=time.time()
        dirpath=os.path.join(os.getcwd(),'screenshot')
        os.makedirs(dirpath,exist_ok=True)
        fielpath=os.path.join(dirpath,f'{str(timstamp).replace('.','')}.PNG')
        screenshot.save(fielpath, format="PNG")
        json_result=get_baidu3_location_json(fielpath)
        return json_result
    def set_window_position(self,exename,destx,desty, width=1016, height=1006):
        try:
            def callback(hwnd, _):
                try:
                    # 获取窗口的进程ID
                    _, pid = win32process.GetWindowThreadProcessId(hwnd)
                    # 获取进程对象
                    process = psutil.Process(pid)
                    # 改进的进程名称匹配方式
                    process_name = process.name().lower()
                    if exename.lower() in process_name:
                        # if win32gui.IsIconic(hwnd):
                        #     win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
                        # # 使用Windows API移动窗口
                        # win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
                        win32gui.MoveWindow(hwnd, destx,desty, width, height, True)
                        # win32gui.MoveWindow(hwnd, destx, desty, width, height, True)
                        # win32gui.SetWindowPos(hwnd, win32con.HWND_TOP, 
                        #                 destx, desty, width, height,
                        #                 win32con.SWP_SHOWWINDOW)
                except (psutil.NoSuchProcess, psutil.AccessDenied, PermissionError):
                    return
                except Exception as e:
                    print(f"进程处理异常: {str(e)}")
                    return
            # 枚举所有窗口
            win32gui.EnumWindows(callback, None)
            return True
        except Exception as e:
            print(f"窗口移动失败: {e}")
            return False
    def close_windows_by_processname(self,processname):
        """关闭所有ziniaobrowser.exe进程的窗口"""
        try:
            def callback(hwnd, _):
                try:
                    # 获取窗口的进程ID
                    _, pid = win32process.GetWindowThreadProcessId(hwnd)
                    # 获取进程对象
                    process = psutil.Process(pid)
                    # 检查进程名称是否包含目标字符串
                    if  processname.lower() in process.name().lower():
                        # 发送关闭消息
                        win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
                except (psutil.NoSuchProcess, psutil.AccessDenied, PermissionError):
                    return
                except Exception as e:
                    print(f"窗口关闭异常: {str(e)}")
                    return
                    
            # 枚举所有窗口
            win32gui.EnumWindows(callback, None)
            return True
        except Exception as e:
            print(f"窗口关闭失败: {e}")
            return False
    def closeEvent(self, event):
        """窗口关闭时停止线程"""
        if self.work_thread and self.work_thread.is_alive():
            self.work_thread.stop()
            self.work_thread.join()
        event.accept()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    
 
    sys.exit(app.exec_())

